﻿namespace PlaylistCopy.Logging
{
    using PlaylistCopy.Contract;
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;

    public class BufferedLogger : ILogger
    {
        public BufferedLogger()
        {
            this.Logs = new ConcurrentQueue<BufferedLoggerEntry>();
        }

        private ConcurrentQueue<BufferedLoggerEntry> Logs { get; set; }

        internal IReadOnlyCollection<BufferedLoggerEntry> Buffer
        {
            get { return new ReadOnlyCollection<BufferedLoggerEntry>(this.Logs.ToList()); }
        }

        public void Error(string message, params object[] args)
        {
            this.Logs.Enqueue(new BufferedLoggerEntry
                              {
                                  Date = DateTime.Now,
                                  Exception = null,
                                  Message = string.Format(message, args),
                                  Type = BufferedLogType.Error
                              });
        }

        public void ErrorException(string message, Exception exception)
        {
            this.Logs.Enqueue(new BufferedLoggerEntry
                              {
                                  Date = DateTime.Now,
                                  Exception = exception,
                                  Message = message,
                                  Type = BufferedLogType.Error
                              });
        }

        public void ErrorException(Exception exception, string message, params object[] args)
        {
            this.ErrorException(string.Format(message, args), exception);
        }

        public void Warning(string message, params object[] args)
        {
            this.Logs.Enqueue(new BufferedLoggerEntry
                              {
                                  Date = DateTime.Now,
                                  Exception = null,
                                  Message = string.Format(message, args),
                                  Type = BufferedLogType.Warning
                              });
        }

        public void WarningException(string message, Exception exception)
        {
            this.Logs.Enqueue(new BufferedLoggerEntry
                              {
                                  Date = DateTime.Now,
                                  Exception = exception,
                                  Message = message,
                                  Type = BufferedLogType.Warning
                              });
        }

        public void WarningException(Exception exception, string message, params object[] args)
        {
            this.WarningException(string.Format(message, args), exception);
        }

        public void Info(string message, params object[] args)
        {
            this.Logs.Enqueue(new BufferedLoggerEntry
                              {
                                  Date = DateTime.Now,
                                  Exception = null,
                                  Message = string.Format(message, args),
                                  Type = BufferedLogType.Info
                              });
        }

        public void InfoException(string message, Exception exception)
        {
            this.Logs.Enqueue(new BufferedLoggerEntry
                              {
                                  Date = DateTime.Now,
                                  Exception = exception,
                                  Message = message,
                                  Type = BufferedLogType.Info
                              });
        }

        public void InfoException(Exception exception, string message, params object[] args)
        {
            this.InfoException(string.Format(message, args), exception);
        }

        public class BufferedLoggerEntry
        {
            public BufferedLogType Type { get; set; }

            public DateTime Date { get; set; }

            public string Message { get; set; }

            public Exception Exception { get; set; }
        }
    }

    public enum BufferedLogType
    {
        Error,
        Warning,
        Info
    }
}
